<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据去重工具</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
    <style>
        body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; }
        .main-container { background: rgba(255, 255, 255, 0.95); border-radius: 15px; box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37); margin: 2rem auto; }
        .upload-area { border: 2px dashed #4361ee; border-radius: 10px; padding: 2rem; text-align: center; background: rgba(67, 97, 238, 0.05); cursor: pointer; }
        .btn-primary { background: linear-gradient(45deg, #4361ee, #3f37c9); border: none; }
        .progress-container, .result-container { display: none; }
    </style>
</head>
<body>
    <div class="container main-container">
        <div class="text-center py-4">
            <h1 class="display-5 fw-bold text-primary">
                <i class="bi bi-file-earmark-binary me-2"></i>智能数据去重工具
            </h1>
            <p class="lead text-muted">支持多种去重算法的可扩展文本去重解决方案</p>
        </div>

        <div class="card mb-4">
            <div class="card-header bg-primary text-white">
                <h5 class="mb-0"><i class="bi bi-upload me-2"></i>文件上传与参数设置</h5>
            </div>
            <div class="card-body">
                <div class="upload-area mb-4" id="uploadArea">
                    <i class="bi bi-cloud-upload display-4 text-primary mb-3"></i>
                    <h5>拖拽文件到此处或点击选择文件</h5>
                    <p class="text-muted">支持JSONL格式文件</p>
                    <input type="file" class="d-none" id="fileInput" accept=".jsonl,.json">
                    <button class="btn btn-outline-primary" id="selectFileBtn">
                        <i class="bi bi-folder2-open me-1"></i>选择文件
                    </button>
                    <div class="mt-2">
                        <small class="text-muted" id="fileName">未选择文件</small>
                    </div>
                </div>

                <!-- 去重方法选择 -->
                <div class="border p-3 mb-4">
                    <h6 class="text-primary mb-3"><i class="bi bi-cpu me-2"></i>去重算法选择</h6>
                    <div class="row">
                        <div class="col-md-6">
                            <label class="form-label">选择去重方法</label>
                            <select class="form-select" id="dedupMethod">
                                <option value="minhash">MinHash + LSH (推荐)</option>
                                <option value="md5">MD5 哈希</option>
                                <option value="exact">精确匹配</option>
                                <option value="simhash">SimHash</option>
                            </select>
                        </div>
                        <div class="col-md-6">
                            <div class="mt-4">
                                <small class="text-muted" id="methodDescription">
                                    基于MinHash和LSH的近似去重算法，适合大规模数据集
                                </small>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="row">
                    <div class="col-md-6">
                        <div class="border p-3 mb-3">
                            <h6 class="text-primary mb-3"><i class="bi bi-sliders me-2"></i>去重参数</h6>
                            <div class="mb-3">
                                <label class="form-label">相似度阈值: <span id="simThresholdValue">0.80</span></label>
                                <input type="range" class="form-range" id="simThreshold" min="0.1" max="1.0" step="0.05" value="0.8">
                            </div>
                            <div class="mb-3">
                                <label class="form-label">最小文本长度</label>
                                <input type="number" class="form-control" id="minLength" value="50" min="10">
                            </div>
                        </div>
                    </div>
                    <div class="col-md-6">
                        <!-- MinHash 算法参数 -->
                        <div class="border p-3 mb-3" id="minhashParams">
                            <h6 class="text-primary mb-3"><i class="bi bi-gear me-2"></i>MinHash 算法参数</h6>
                            <div class="row">
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">N-gram大小</label>
                                    <input type="number" class="form-control" id="ngramN" value="3" min="2" max="10">
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">Bands数量</label>
                                    <input type="number" class="form-control" id="bandsSize" value="3" min="1" max="20">
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">签名长度</label>
                                    <input type="number" class="form-control" id="signatureLen" value="100" min="50" max="500">
                                </div>
                            </div>
                        </div>

                        <!-- MD5 算法参数 -->
                        <div class="border p-3 mb-3" id="md5Params" style="display: none;">
                            <h6 class="text-primary mb-3"><i class="bi bi-gear me-2"></i>MD5 算法参数</h6>
                            <div class="row">
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">大小写敏感</label>
                                    <select class="form-select" id="md5CaseSensitive">
                                        <option value="true">是</option>
                                        <option value="false" selected>否</option>
                                    </select>
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">忽略空白字符</label>
                                    <select class="form-select" id="md5StripWhitespace">
                                        <option value="true" selected>是</option>
                                        <option value="false">否</option>
                                    </select>
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">标准化Unicode</label>
                                    <select class="form-select" id="md5NormalizeUnicode">
                                        <option value="true" selected>是</option>
                                        <option value="false">否</option>
                                    </select>
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">哈希长度 (字节)</label>
                                    <input type="number" class="form-control" id="md5HashLength" value="16" min="1" max="16">
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">使用滚动哈希</label>
                                    <select class="form-select" id="md5UseRollingHash">
                                        <option value="true">是</option>
                                        <option value="false" selected>否</option>
                                    </select>
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">窗口大小</label>
                                    <input type="number" class="form-control" id="md5WindowSize" value="50" min="10" max="1000">
                                </div>
                            </div>
                        </div>

                        <!-- 精确匹配算法参数 -->
                        <div class="border p-3 mb-3" id="exactParams" style="display: none;">
                            <h6 class="text-primary mb-3"><i class="bi bi-gear me-2"></i>精确匹配参数</h6>
                            <div class="row">
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">大小写敏感</label>
                                    <select class="form-select" id="caseSensitive">
                                        <option value="true">是</option>
                                        <option value="false" selected>否</option>
                                    </select>
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">忽略空白字符</label>
                                    <select class="form-select" id="ignoreWhitespace">
                                        <option value="true" selected>是</option>
                                        <option value="false">否</option>
                                    </select>
                                </div>
                            </div>
                        </div>

                        <!-- SimHash 算法参数 -->
                        <div class="border p-3 mb-3" id="simhashParams" style="display: none;">
                            <h6 class="text-primary mb-3"><i class="bi bi-gear me-2"></i>SimHash 算法参数</h6>
                            <div class="row">
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">位数</label>
                                    <select class="form-select" id="simhashBits">
                                        <option value="64" selected>64</option>
                                        <option value="128">128</option>
                                    </select>
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">最大汉明距离</label>
                                    <input type="number" class="form-control" id="simhashMaxHamming" value="3" min="0" max="16">
                                </div>
                                <div class="col-md-6 mb-3">
                                    <label class="form-label">分词方式</label>
                                    <select class="form-select" id="simhashTokenizer">
                                        <option value="word" selected>按词</option>
                                        <option value="char">按字符n-gram</option>
                                    </select>
                                </div>
                                <div class="col-md-6 mb-3" id="simhashNgramWrap" style="display: none;">
                                    <label class="form-label">n-gram大小</label>
                                    <input type="number" class="form-control" id="simhashNgramN" value="3" min="2" max="10">
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                    <div class="text-center">
                        <button class="btn btn-primary btn-lg me-2" id="processBtn">
                            <i class="bi bi-play-circle me-2"></i>开始去重处理
                        </button>
                        <button class="btn btn-danger btn-lg" id="stopBtn" style="display: none;">
                            <i class="bi bi-stop-circle me-2"></i>停止处理
                        </button>
                    </div>
            </div>
        </div>

        <div class="progress-container" id="progressContainer">
            <div class="card mb-4">
                <div class="card-header bg-info text-white">
                    <h5 class="mb-0"><i class="bi bi-speedometer2 me-2"></i>处理进度</h5>
                </div>
                <div class="card-body">
                    <!-- 当前阶段显示 -->
                    <div class="mb-3">
                        <h6 class="text-primary" id="currentPhase">准备处理...</h6>
                    </div>
                    
                    <!-- 阶段进度条 -->
                    <div class="mb-3">
                        <div class="d-flex justify-content-between">
                            <span id="phaseProgressMessage">准备处理...</span>
                            <span id="phaseProgressPercent">0%</span>
                        </div>
                        <div class="progress" style="height: 20px;">
                            <div class="progress-bar progress-bar-striped progress-bar-animated" 
                                 role="progressbar" id="phaseProgressBar" style="width: 0%;">
                            </div>
                        </div>
                    </div>
                    
                    <!-- 总体进度 -->
                    <div class="mb-3">
                        <div class="d-flex justify-content-between">
                            <span>总体进度</span>
                            <span id="overallProgressPercent">0%</span>
                        </div>
                        <div class="progress" style="height: 15px;">
                            <div class="progress-bar bg-secondary" 
                                 role="progressbar" id="overallProgressBar" style="width: 0%;">
                            </div>
                        </div>
                    </div>
                    
                    <!-- 阶段列表 -->
                    <div class="mb-3">
                        <div class="row">
                            <div class="col-3">
                                <div class="text-center p-2 bg-light rounded" id="phase1">
                                    <small>文件读取</small>
                                </div>
                            </div>
                            <div class="col-3">
                                <div class="text-center p-2 bg-light rounded" id="phase2">
                                    <small>数据过滤</small>
                                </div>
                            </div>
                            <div class="col-3">
                                <div class="text-center p-2 bg-light rounded" id="phase3">
                                    <small>去重处理</small>
                                </div>
                            </div>
                            <div class="col-3">
                                <div class="text-center p-2 bg-light rounded" id="phase4">
                                    <small>结果构建</small>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <div class="text-center">
                        <div class="spinner-border text-primary" role="status" id="loadingSpinner">
                            <span class="visually-hidden">处理中...</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="result-container" id="resultContainer">
            <div class="card">
                <div class="card-header bg-success text-white">
                    <h5 class="mb-0"><i class="bi bi-check-circle me-2"></i>处理完成</h5>
                </div>
                <div class="card-body">
                    <div class="row mb-4">
                        <div class="col-md-3 mb-3">
                            <div class="border p-3 text-center">
                                <h3 class="text-primary mb-0" id="originalCount">0</h3>
                                <p class="mb-0">原始数据量</p>
                            </div>
                        </div>
                        <div class="col-md-3 mb-3">
                            <div class="border p-3 text-center">
                                <h3 class="text-success mb-0" id="dedupedCount">0</h3>
                                <p class="mb-0">去重后数据量</p>
                            </div>
                        </div>
                        <div class="col-md-3 mb-3">
                            <div class="border p-3 text-center">
                                <h3 class="text-warning mb-0" id="duplicateCount">0</h3>
                                <p class="mb-0">重复数据量</p>
                            </div>
                        </div>
                        <div class="col-md-3 mb-3">
                            <div class="border p-3 text-center">
                                <h3 class="text-info mb-0" id="duplicatePairsCount">0</h3>
                                <p class="mb-0">相似对数量</p>
                            </div>
                        </div>
                    </div>

                    <div class="row">
                        <div class="col-md-4 mb-3">
                            <div class="border p-3">
                                <h6><i class="bi bi-file-earmark-text text-primary me-2"></i>去重结果文件</h6>
                                <button class="btn btn-success w-100" id="downloadResult">
                                    <i class="bi bi-download me-1"></i>下载结果
                                </button>
                            </div>
                        </div>
                        <div class="col-md-4 mb-3">
                            <div class="border p-3">
                                <h6><i class="bi bi-file-earmark-x text-warning me-2"></i>被过滤数据</h6>
                                <button class="btn btn-warning w-100" id="downloadFiltered">
                                    <i class="bi bi-download me-1"></i>下载过滤数据
                                </button>
                            </div>
                        </div>
                        <div class="col-md-4 mb-3">
                            <div class="border p-3">
                                <h6><i class="bi bi-file-earmark-binary text-info me-2"></i>相似对详情</h6>
                                <button class="btn btn-info w-100" id="downloadPairs">
                                    <i class="bi bi-download me-1"></i>下载相似对
                                </button>
                            </div>
                        </div>
                    </div>

                    <div class="text-center mt-4">
                        <button class="btn btn-outline-primary" id="resetBtn">
                            <i class="bi bi-arrow-repeat me-2"></i>重新处理其他文件
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        let taskId = null;
        let pollInterval = null;
        let currentPhase = 0;
        let totalPhases = 4;

        // 显示Toast提示
        function showToast(title, message) {
            alert(title + ": " + message);
        }

        // 处理文件选择
        function handleFileSelect(event) {
            const file = event.target.files[0];
            if (file) {
                document.getElementById('fileName').textContent = file.name;
            } else {
                document.getElementById('fileName').textContent = '未选择文件';
            }
        }

        // 显示进度
        function showProgress() {
            document.querySelector('.progress-container').style.display = 'block';
            document.querySelector('.result-container').style.display = 'none';
            document.getElementById('processBtn').style.display = 'none';
            document.getElementById('stopBtn').style.display = 'inline-block';
            resetPhaseDisplay();
        }

        // 重置阶段显示
        function resetPhaseDisplay() {
            currentPhase = 0;
            // 重置所有阶段样式
            for (let i = 1; i <= totalPhases; i++) {
                const phaseElement = document.getElementById(`phase${i}`);
                if (phaseElement) {
                    phaseElement.className = 'text-center p-2 bg-light rounded';
                }
            }
            // 重置进度条
            document.getElementById('phaseProgressBar').style.width = '0%';
            document.getElementById('phaseProgressPercent').textContent = '0%';
            document.getElementById('overallProgressBar').style.width = '0%';
            document.getElementById('overallProgressPercent').textContent = '0%';
            document.getElementById('currentPhase').textContent = '准备处理...';
            document.getElementById('phaseProgressMessage').textContent = '准备处理...';
        }

        // 更新阶段显示
        function updatePhaseDisplay(phase, subProgress, subMessage, overallProgress) {
            // 更新当前阶段
            if (phase !== currentPhase) {
                // 完成上一阶段
                if (currentPhase > 0) {
                    const prevPhaseElement = document.getElementById(`phase${currentPhase}`);
                    if (prevPhaseElement) {
                        prevPhaseElement.className = 'text-center p-2 bg-success text-white rounded';
                    }
                }
                currentPhase = phase;
                // 高亮当前阶段
                const currentPhaseElement = document.getElementById(`phase${currentPhase}`);
                if (currentPhaseElement) {
                    currentPhaseElement.className = 'text-center p-2 bg-primary text-white rounded';
                }
            }
            
            // 更新阶段进度条
            document.getElementById('phaseProgressBar').style.width = subProgress + '%';
            document.getElementById('phaseProgressPercent').textContent = subProgress + '%';
            document.getElementById('phaseProgressMessage').textContent = subMessage;
            
            // 更新总体进度条
            document.getElementById('overallProgressBar').style.width = overallProgress + '%';
            document.getElementById('overallProgressPercent').textContent = overallProgress + '%';
            
            // 更新当前阶段标题
            const phaseNames = ['准备处理', '文件读取', '数据过滤', '去重处理', '结果构建'];
            if (phase < phaseNames.length) {
                document.getElementById('currentPhase').textContent = phaseNames[phase];
            }
        }

        // 显示结果
        function showResult(stats) {
            document.querySelector('.result-container').style.display = 'block';
            document.querySelector('.progress-container').style.display = 'none';
            document.getElementById('processBtn').style.display = 'inline-block';
            document.getElementById('stopBtn').style.display = 'none';
            document.getElementById('originalCount').textContent = stats.original_count || 0;
            document.getElementById('dedupedCount').textContent = stats.deduped_count || 0;
            document.getElementById('duplicateCount').textContent = stats.duplicate_count || 0;
            document.getElementById('duplicatePairsCount').textContent = stats.duplicate_pairs_count || 0;
        }

        // 更新方法描述和参数显示
        function updateMethodDisplay() {
            const method = document.getElementById('dedupMethod').value;
            const description = document.getElementById('methodDescription');
            const minhashParams = document.getElementById('minhashParams');
            const md5Params = document.getElementById('md5Params');
            const exactParams = document.getElementById('exactParams');
            const simhashParams = document.getElementById('simhashParams');
            const simThreshold = document.getElementById('simThreshold');
            const simThresholdValue = document.getElementById('simThresholdValue');

            if (method === 'minhash') {
                description.textContent = '基于MinHash和LSH的近似去重算法，适合大规模数据集';
                minhashParams.style.display = 'block';
                md5Params.style.display = 'none';
                exactParams.style.display = 'none';
                simhashParams.style.display = 'none';
                simThreshold.disabled = false;
                simThresholdValue.textContent = parseFloat(simThreshold.value).toFixed(2);
            } else if (method === 'md5') {
                description.textContent = '基于MD5哈希的去重算法，支持精确和近似去重模式';
                minhashParams.style.display = 'none';
                md5Params.style.display = 'block';
                exactParams.style.display = 'none';
                simhashParams.style.display = 'none';
                simThreshold.disabled = false;
                simThresholdValue.textContent = parseFloat(simThreshold.value).toFixed(2);
            } else if (method === 'exact') {
                description.textContent = '基于精确文本匹配的去重算法，适合小规模高精度需求';
                minhashParams.style.display = 'none';
                md5Params.style.display = 'none';
                exactParams.style.display = 'block';
                simhashParams.style.display = 'none';
                simThreshold.disabled = true;
                simThresholdValue.textContent = '1.00';
            } else if (method === 'simhash') {
                description.textContent = '基于SimHash的近似去重算法，按汉明距离阈值聚类';
                minhashParams.style.display = 'none';
                md5Params.style.display = 'none';
                exactParams.style.display = 'none';
                simhashParams.style.display = 'block';
                simThreshold.disabled = true;
                simThresholdValue.textContent = '—';
            }
        }

        // 处理文件上传
        async function processFile() {
            const fileInput = document.getElementById('fileInput');
            if (!fileInput.files[0]) {
                showToast('错误', '请先选择文件');
                return;
            }

            showProgress();
            updatePhaseDisplay(0, 0, '准备上传文件...', 0);

            const formData = new FormData();
            formData.append('file', fileInput.files[0]);
            // 使用后端的 dedup_method 字段
            formData.append('dedup_method', document.getElementById('dedupMethod').value);
            formData.append('sim_threshold', document.getElementById('simThreshold').value);
            formData.append('min_length', document.getElementById('minLength').value);

            // 根据选择的方法添加相应的参数
            const method = document.getElementById('dedupMethod').value;
            if (method === 'minhash') {
                formData.append('ngram_n', document.getElementById('ngramN').value);
                formData.append('band_size', document.getElementById('bandsSize').value);
                formData.append('signature_len', document.getElementById('signatureLen').value);
            } else if (method === 'md5') {
                formData.append('case_sensitive', document.getElementById('md5CaseSensitive').value);
                formData.append('strip_whitespace', document.getElementById('md5StripWhitespace').value);
                formData.append('normalize_unicode', document.getElementById('md5NormalizeUnicode').value);
                formData.append('hash_length', document.getElementById('md5HashLength').value);
                formData.append('use_rolling_hash', document.getElementById('md5UseRollingHash').value);
                formData.append('window_size', document.getElementById('md5WindowSize').value);
            } else if (method === 'exact') {
                formData.append('case_sensitive', document.getElementById('caseSensitive').value);
                formData.append('strip_whitespace', document.getElementById('ignoreWhitespace').value);
            } else if (method === 'simhash') {
                formData.append('bits', document.getElementById('simhashBits').value);
                formData.append('max_hamming_distance', document.getElementById('simhashMaxHamming').value);
                formData.append('tokenizer', document.getElementById('simhashTokenizer').value);
                if (document.getElementById('simhashTokenizer').value === 'char') {
                    formData.append('ngram_n', document.getElementById('simhashNgramN').value);
                }
            }

            try {
                const response = await fetch('/upload', {
                    method: 'POST',
                    body: formData
                });

                const data = await response.json();
                if (data.error) {
                    throw new Error(data.error);
                }

                taskId = data.task_id;
                startPolling();
            } catch (error) {
                updatePhaseDisplay(0, 0, '上传失败: ' + error.message, 0);
                showToast('错误', error.message);
                // 恢复按钮显示
                document.getElementById('processBtn').style.display = 'inline-block';
                document.getElementById('stopBtn').style.display = 'none';
            }
        }

        // 停止处理
        async function stopProcessing() {
            if (!taskId) {
                return;
            }

            try {
                const response = await fetch(`/stop/${taskId}`, {
                    method: 'POST'
                });

                const data = await response.json();
                if (data.error) {
                    showToast('错误', data.error);
                } else {
                    clearInterval(pollInterval);
                    updatePhaseDisplay(currentPhase, 0, '用户手动停止处理', 0);
                    // 恢复按钮显示
                    document.getElementById('processBtn').style.display = 'inline-block';
                    document.getElementById('stopBtn').style.display = 'none';
                    showToast('提示', '已发送停止请求');
                }
            } catch (error) {
                showToast('错误', '停止请求失败: ' + error.message);
            }
        }

        // 轮询处理状态
        function startPolling() {
            pollInterval = setInterval(async () => {
                try {
                    const response = await fetch(`/status/${taskId}`);
                    const data = await response.json();

                    if (data.status === 'completed') {
                        clearInterval(pollInterval);
                        // 完成所有阶段
                        updatePhaseDisplay(4, 100, '处理完成', 100);
                        showResult(data.result.stats);
                        showToast('提示', '处理完成');
                    } else if (data.status === 'failed') {
                        clearInterval(pollInterval);
                        updatePhaseDisplay(currentPhase, 0, '处理失败: ' + data.error, 0);
                        showToast('错误', data.error);
                        // 恢复按钮显示
                        document.getElementById('processBtn').style.display = 'inline-block';
                        document.getElementById('stopBtn').style.display = 'none';
                    } else if (data.status === 'stopped') {
                        clearInterval(pollInterval);
                        updatePhaseDisplay(currentPhase, 0, '用户手动停止处理', 0);
                        showToast('提示', '处理已停止');
                        // 恢复按钮显示
                        document.getElementById('processBtn').style.display = 'inline-block';
                        document.getElementById('stopBtn').style.display = 'none';
                    } else {
                        // 解析进度信息，格式如 "读取文件内容... (150/1000)"
                        let phase = currentPhase;
                        let subProgress = 0;
                        let overallProgress = data.progress || 0;
                        let message = data.message || '处理中...';
                        
                        // 根据消息内容判断阶段
                        if (message.includes('读取文件')) {
                            phase = 1;
                        } else if (message.includes('过滤')) {
                            phase = 2;
                        } else if (message.includes('去重') || message.includes('LSH')) {
                            phase = 3;
                        } else if (message.includes('构建') || message.includes('输出')) {
                            phase = 4;
                        }
                        
                        // 解析具体进度 (150/1000)
                        const progressMatch = message.match(/\((\d+)\/(\d+)\)/);
                        if (progressMatch) {
                            const current = parseInt(progressMatch[1]);
                            const total = parseInt(progressMatch[2]);
                            if (total > 0) {
                                subProgress = Math.round((current / total) * 100);
                            }
                        }
                        
                        updatePhaseDisplay(phase, subProgress, message, overallProgress);
                    }
                } catch (error) {
                    clearInterval(pollInterval);
                    updatePhaseDisplay(currentPhase, 0, '轮询失败: ' + error.message, 0);
                    showToast('错误', error.message);
                    // 恢复按钮显示
                    document.getElementById('processBtn').style.display = 'inline-block';
                    document.getElementById('stopBtn').style.display = 'none';
                }
            }, 1000);
        }

            // 初始化事件监听器
            document.addEventListener('DOMContentLoaded', function() {
                // 文件选择相关
                document.getElementById('selectFileBtn').addEventListener('click', () => {
                    document.getElementById('fileInput').click();
                });

                document.getElementById('fileInput').addEventListener('change', handleFileSelect);

                // 参数滑块
                document.getElementById('simThreshold').addEventListener('input', (e) => {
                    document.getElementById('simThresholdValue').textContent = parseFloat(e.target.value).toFixed(2);
                });

                // 去重方法切换
                document.getElementById('dedupMethod').addEventListener('change', updateMethodDisplay);

                // SimHash 分词方式切换
                const simhashTokenizer = document.getElementById('simhashTokenizer');
                if (simhashTokenizer) {
                    simhashTokenizer.addEventListener('change', () => {
                        const wrap = document.getElementById('simhashNgramWrap');
                        if (simhashTokenizer.value === 'char') {
                            wrap.style.display = 'block';
                        } else {
                            wrap.style.display = 'none';
                        }
                    });
                }

                // 处理按钮
                document.getElementById('processBtn').addEventListener('click', processFile);

                // 停止按钮
                document.getElementById('stopBtn').addEventListener('click', stopProcessing);

                // 下载按钮
                document.getElementById('downloadResult').addEventListener('click', () => {
                    if (taskId) window.open(`/download/${taskId}/result`, '_blank');
                });

                document.getElementById('downloadFiltered').addEventListener('click', () => {
                    if (taskId) window.open(`/download/${taskId}/filtered`, '_blank');
                });

                document.getElementById('downloadPairs').addEventListener('click', () => {
                    if (taskId) window.open(`/download/${taskId}/pairs`, '_blank');
                });

                // 重置按钮
                document.getElementById('resetBtn').addEventListener('click', () => {
                    document.querySelector('.result-container').style.display = 'none';
                    document.getElementById('fileInput').value = '';
                    document.getElementById('fileName').textContent = '未选择文件';
                    document.getElementById('processBtn').style.display = 'inline-block';
                    document.getElementById('stopBtn').style.display = 'none';
                    resetPhaseDisplay();
                });

                // 拖拽上传
                const uploadArea = document.getElementById('uploadArea');
                uploadArea.addEventListener('dragover', (e) => {
                    e.preventDefault();
                    uploadArea.classList.add('bg-light');
                });

                uploadArea.addEventListener('dragleave', () => {
                    uploadArea.classList.remove('bg-light');
                });

                uploadArea.addEventListener('drop', (e) => {
                    e.preventDefault();
                    uploadArea.classList.remove('bg-light');
                    if (e.dataTransfer.files.length) {
                        document.getElementById('fileInput').files = e.dataTransfer.files;
                        handleFileSelect({ target: document.getElementById('fileInput') });
                    }
                });

                // 初始化方法显示
                updateMethodDisplay();
            });
    </script>


</body>
</html>
